package com.fate.system.service.impl;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fate.framework.annotation.TransferDict;
import com.fate.framework.dto.TreeNodeDTO;
import com.fate.framework.utils.CommonUtil;
import com.fate.system.entity.Dict;
import com.fate.system.mapper.DictMapper;
import com.fate.system.service.IDictService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class DictServiceImpl extends ServiceImpl<DictMapper, Dict> implements IDictService {

  @Override
  public List<Dict> getDictByType(String type) {
    return this.lambdaQuery().eq(Dict::getType, type).list();
  }

  @Override
  public <E> void transfer(E e) {
    Map<Map.Entry<String, String>, Dict> sign2Dict =
        this.lambdaQuery()
            .select(Dict::getType, Dict::getValue, Dict::getDescription)
            .list()
            .stream()
            .collect(
                Collectors.toMap(
                    dict -> new AbstractMap.SimpleEntry<>(dict.getType(), dict.getValue()),
                    Function.identity()));

    if (e instanceof Collection<?>) {
      ((Collection<?>) e).forEach(obj -> processObject(obj, sign2Dict));
    } else {
      processObject(e, sign2Dict);
    }
  }

  private <E> void processObject(E e, Map<Map.Entry<String, String>, Dict> sign2Dict) {
    Class<?> aClass = e.getClass();
    Field[] fieldItems = aClass.getDeclaredFields();

    if (CommonUtil.notNullOrEmpty(fieldItems)) {
      for (Field fieldItem : fieldItems) {
        TransferDict annotation = fieldItem.getAnnotation(TransferDict.class);
        if (CommonUtil.isNullOrEmpty(annotation)) {
          continue;
        }
        String type = annotation.type();
        String field = annotation.field();

        try {
          Field f = aClass.getDeclaredField(field);
          f.setAccessible(true);
          Object fieldValue = f.get(e);

          if (CommonUtil.isNullOrEmpty(fieldValue)) {
            continue;
          }

          // 处理String和Integer类型
          if (fieldValue instanceof String || fieldValue instanceof Integer) {
            translateFieldValue(fieldItem, e, sign2Dict, type, fieldValue.toString());
          }

          // 处理List<String>或List<Integer>
          if (fieldValue instanceof List<?>) {
            List<?> list = (List<?>) fieldValue;
            List<String> translatedList =
                list.stream()
                    .map(
                        item -> sign2Dict.get(new AbstractMap.SimpleEntry<>(type, item.toString())))
                    .filter(Objects::nonNull)
                    .map(Dict::getDescription)
                    .collect(Collectors.toList());
            fieldItem.setAccessible(true);
            fieldItem.set(e, translatedList);
          }

          // 处理String[]或Integer[]
          if (fieldValue.getClass().isArray()) {
            int length = Array.getLength(fieldValue);
            String[] translatedArray = new String[length];
            for (int i = 0; i < length; i++) {
              Object item = Array.get(fieldValue, i);
              Dict dict = sign2Dict.get(new AbstractMap.SimpleEntry<>(type, item.toString()));
              translatedArray[i] = dict != null ? dict.getDescription() : item.toString();
            }
            fieldItem.setAccessible(true);
            fieldItem.set(e, translatedArray);
          }

        } catch (Exception ex) {
          log.error("字典转换错误", ex);
        }
      }
    }

    // 递归处理子节点
    if (e instanceof TreeNodeDTO treeNodeDTO) {
      List<TreeNodeDTO> children = treeNodeDTO.getChildren();
      if (CommonUtil.notNullOrEmpty(children)) {
        children.forEach(child -> processObject(child, sign2Dict));
      }
    }
  }

  private <E> void translateFieldValue(
      Field fieldItem,
      E e,
      Map<Map.Entry<String, String>, Dict> sign2Dict,
      String type,
      String value)
      throws IllegalAccessException {
    Dict dict = sign2Dict.get(new AbstractMap.SimpleEntry<>(type, value));
    if (dict != null && Objects.equals(dict.getValue(), value)) {
      fieldItem.setAccessible(true);
      fieldItem.set(e, dict.getDescription());
    }
  }

  @Override
  public <E> void transfer(Page<E> e) {
    transfer(e.getRecords());
  }
}
